#include<mcache.h>
#include<unistd.h>

static soc_stat *fd2stat[MAX_FD];
/**
 * 命令解析调用入口
 * socket_regist 注册一个新的socket文件描述符
 * 
*/
void socket_regist(int socfd){
    assert(socfd >= 0 && socfd < MAX_FD);
    assert(fd2stat[socfd] == 0);

    auto tmp = (soc_stat *)malloc(sizeof(soc_stat));
    tmp->buffer_cur = 0;
    tmp->parse_cur = 0;
    tmp->socfd = socfd;
    tmp->amstat = WAIT_CMD;

    fd2stat[socfd] = tmp;
}

/**
 * 命令解析调用入口
 * socket_in 当连接缓存区有内容，就调用socket in
 * 
*/
void socket_in(int socfd){
    soc_stat *socstat = fd2stat[socfd];
    int cmd_token;
    char *tmp_nxpc;
    LOG_MSG("CALL SOCK IN");
    while (1)
    {
        switch (socstat->amstat)
        {
        case WAIT_CMD:
            socstat->buffer_cur += read(socfd, socstat->buffer, MAX_BUFFER_SIZE - socstat->buffer_cur);
            if (socstat->buffer_cur == MAX_BUFFER_SIZE)
            {
                socstat->amstat = CMD_OVER;
                parse_error(socstat, ERR_CLIENT, "TOO LONG CMD");
                break;
            }
            socstat->amstat = CMD_PARSE;
            break;
        case CMD_PARSE:
            //命令解析
            //首先解析一个text line
            tmp_nxpc = (char *)memchr(socstat->buffer + socstat->parse_cur, '\n', socstat->buffer_cur - socstat->parse_cur);
            if (tmp_nxpc == NULL)
            {
                socstat->amstat = WAIT_MORE;
                break;
            }
            socstat->parse_end = tmp_nxpc - socstat->buffer;
            if (tmp_nxpc == socstat->buffer || *(tmp_nxpc - 1) != '\r')
            {
                socstat->amstat = CMD_OVER;
                parse_error(socstat, ERR_CLIENT, "CMD NEED END WITH rn");
                break;
            }

            // textline划分token
            char *tokens[MAX_TOKEN_NUM];
            cmd_token = parse_cmd_split(socstat->buffer, socstat->parse_cur, socstat->parse_end - 1, tokens);
            if (cmd_token <= 0)
            {
                parse_error(socstat, ERR_CLIENT, "IVALIED CMD TOKEN NUM");
                socstat->amstat = CMD_OVER;
                break;
            }

            //按token解析
            if (strcmp(tokens[0], "set") == 0)
            {
                LOG_MSG("ADD SET");
            }
            else if (strcmp(tokens[0], "get") == 0)
            {
                LOG_MSG("ADD GET");
            }
            else if (strcmp(tokens[0], "delete") == 0)
            {
                LOG_MSG("ADD DEL");
            }
            else
            {
                parse_error(socstat, ERR_CLIENT, "INVALID CMD VERB");
                socstat->amstat = CMD_OVER;
                break;
            }

            break;
        case WORKING:
            parse_error(socstat, ERR_SERVER, "SERVER IS WORKING");
            return;
        case WAIT_MORE:
            socstat->amstat = WAIT_CMD;
            return;
        case CMD_OVER:
            socstat->parse_cur = socstat->parse_end + 1;
            if (socstat->buffer_cur == socstat->parse_cur)
            {
                socstat->buffer_cur = 0;
                socstat->parse_cur = 0;
            }
            socstat->amstat = WAIT_CMD;
            break;
        }
    }
}

/**
 * int parse_cmd_split(char* buffer,int beg,int end,char**)
 * 把一段text line按照空格分开 返回char*数组的长度，若大于MAX_TOKEN_NUM返回-1
 * 并且把首个空格换为空字符\0 beg,end前闭后开
 */
int parse_cmd_split(char*buffer,int beg,int end,char ** toks){
    int ret = 0;
    int cur=beg;
    int pre=cur;
    while (cur < end){
        if(buffer[cur++]!=' ') continue;
        if(cur==pre+1){
            pre++;
            continue;
        }
        buffer[cur - 1] = '\0';
        pre = cur;
        toks[ret++] = buffer + cur-1;
        if(ret>=MAX_TOKEN_NUM)
            return -1;
    }
    return ret;
}

/**
 * parse_error
 * 指定socket发送错误信息
 * 
*/
void parse_error(soc_stat *socstat,err_case err_stat,const string &cs){
    string tmps;
    switch (err_stat)
    {
    case ERR_SERVER:
        tmps += "SERVER_ERROR ";
        tmps += cs;
        break;
    case ERR_CLIENT:
        tmps += "CLIENT_ERROR ";
        tmps += cs;
        break;
    case ERR_CMD:
        tmps += "ERROR";
        break;
    }
    tmps += "\r\n";
    write(socstat->socfd, tmps.c_str(), tmps.size());
}